package org.kabanyo.components {

	import flash.events.Event;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;

	import mx.collections.ArrayCollection;
	import mx.collections.IList;

	import org.kabanyo.events.AutoCompleteEvent;

	import spark.components.Button;
	import spark.components.List;
	import spark.components.TextInput;

	/**
	 * List with autocomplete text input.
	 *
	 * @author Desky Natalio
	 */

	//Events
	[Event(name="searching", type="org.kabanyo.events.AutoCompleteEvent")]
	[Event(name="clearingText", type="org.kabanyo.events.AutoCompleteEvent")]
	[Event(name="itemSelected", type="org.kabanyo.events.AutoCompleteEvent")]

	//Skin Component States
	[SkinState("searching")]
	[SkinState("selected")]
	[SkinState("normalWithAutoSearch")]
	[SkinState("searchingWithAutoSearch")]
	[SkinState("selectedWithAutoSearch")]
	[SkinState("disabledWithAutoSearch")]

	public class AutoComplete extends List {
		//---------------
		//Static Constant
		//---------------
		public static const DEFAULT_AUTO_SEARCH:Boolean=true;
		public static const DEFAULT_FIRST_INDEX:uint=0;
		public static const DEFAULT_MATCH:String="matchAnyPart";
		public static const DEFAULT_SEARCH_ENABLED:Boolean=false;
		public static const DEFAULT_SEARCHING_TEXT:String="";
		public static const DEFAULT_SELECTED_INDEX:int=-1;
		public static const DEFAULT_FILTER_ENABLED:Boolean=true;

		public static const MATCH_ANY_PART:String="matchAnyPart";
		public static const MATCH_BEGINNING:String="matchBeginning";

		public static const MAX_ROW_FILTERED_DATA:uint=5;

		//---------
		//Skin Part
		//---------
		[SkinPart(required="false")]
		public var textInput:TextInput;

		[SkinPart(required="false")]
		public var clearButton:Button;

		[SkinPart(required="false")]
		public var searchButton:Button;

		//----------
		//Properties
		//----------
		private var _autoSearch:Boolean=DEFAULT_AUTO_SEARCH;

		[Bindable]
		public function get autoSearch():Boolean {
			return _autoSearch;
		}

		public function set autoSearch(value:Boolean):void {
			_autoSearch=value;
			_searchEnabled=value;
		}

		private var _searchEnabled:Boolean=DEFAULT_SEARCH_ENABLED;

		public function get searchEnabled():Boolean {
			return _searchEnabled;
		}

		private var _searchingText:String;

		[Bindable]
		public function get searchingText():String {
			return _searchingText;
		}

		public function set searchingText(value:String):void {
			_searchingText=value;
		}

		private var _match:String=DEFAULT_MATCH;

		[Inspectable(enumeration="anypart,beginning")]
		public function set match(value:String):void {
			switch (value) {
				case "anypart":  {
					value=MATCH_ANY_PART;
					break;
				}
				case "beginning":  {
					value=MATCH_BEGINNING;
					break;
				}
				default:  {
					value=MATCH_ANY_PART;
					break;
				}
			}
			_match=value;
		}

		public function get match():String {
			return _match;
		}

		private var _filterFunction:Function;

		public function get filterFunction():Function {
			return _filterFunction;
		}

		public function set filterFunction(value:Function):void {
			_filterFunction=value;
			ArrayCollection(super.dataProvider).filterFunction=value;
		}

		private var _filterEnabled:Boolean=DEFAULT_FILTER_ENABLED;

		public function get filterEnabled():Boolean {
			return _filterEnabled;
		}

		public function set filterEnabled(value:Boolean):void {
			_filterEnabled=value;
		}

		override public function set dataProvider(value:IList):void {
			if (filterEnabled && value is ArrayCollection) {
				if (filterFunction != null) {
					(value as ArrayCollection).filterFunction=filterFunction;
				} else {
					(value as ArrayCollection).filterFunction=filterDataProvider;
				}
			}
			super.dataProvider=value;
		}

		//-----------
		//Constructor
		//-----------
		public function AutoComplete() {
			super();
			//setStyle("skinClass", AutoCompleteSkin);
		}

		//-------
		//Methods
		//-------
		override protected function getCurrentSkinState():String {
			var state:String;
			if (!enabled) {
				state="disabled";
			} else if (searchingText != DEFAULT_SEARCHING_TEXT && selectedIndex == DEFAULT_SELECTED_INDEX && searchEnabled) {
				state="searching";
			} else if (searchingText != DEFAULT_SEARCHING_TEXT && selectedIndex != DEFAULT_SELECTED_INDEX) {
				state="selected";
			} else {
				state="normal";
			}
			if (autoSearch) {
				state+="WithAutoSearch";
			}
			return state;
		}

		override protected function partAdded(partName:String, instance:Object):void {
			super.partAdded(partName, instance);
			if (instance == textInput) {
				textInput.addEventListener(KeyboardEvent.KEY_DOWN, textInput_keyDownHandler);
				textInput.addEventListener(KeyboardEvent.KEY_UP, textInput_keyUpHandler);
			}
			if (instance == clearButton) {
				clearButton.addEventListener(MouseEvent.CLICK, clearButton_clickHandler);
			}
			if (instance == searchButton) {
				searchButton.addEventListener(MouseEvent.CLICK, searchButton_clickHandler);
			}
			if (instance == dataGroup) {
				//				if (filterEnabled && dataProvider != null && dataProvider is ArrayCollection) {
				//					if (filterFunction != null) {
				//						(dataProvider as ArrayCollection).filterFunction = filterFunction;
				//					} else {
				//						(dataProvider as ArrayCollection).filterFunction = filterDataProvider;
				//					}
				//				}
				dataGroup.addEventListener(KeyboardEvent.KEY_DOWN, dataGroup_keyDownHandler);
				dataGroup.addEventListener(Event.CHANGE, dataGroup_changeHandler);
				dataGroup.addEventListener(MouseEvent.CLICK, dataGroup_clickHandler);
			}
		}

		override protected function partRemoved(partName:String, instance:Object):void {
			super.partRemoved(partName, instance);
			if (instance == textInput) {
				textInput.removeEventListener(KeyboardEvent.KEY_DOWN, textInput_keyDownHandler);
				textInput.removeEventListener(KeyboardEvent.KEY_UP, textInput_keyUpHandler);
			}
			if (instance == clearButton) {
				clearButton.removeEventListener(MouseEvent.CLICK, clearButton_clickHandler);
			}
			if (instance == searchButton) {
				searchButton.removeEventListener(MouseEvent.CLICK, searchButton_clickHandler);
			}
			if (instance == dataGroup) {
				dataGroup.removeEventListener(KeyboardEvent.KEY_DOWN, dataGroup_keyDownHandler);
				dataGroup.removeEventListener(Event.CHANGE, dataGroup_changeHandler);
				dataGroup.removeEventListener(MouseEvent.CLICK, dataGroup_clickHandler);
			}
		}

		public function clearText():void {
			dispatchEvent(new AutoCompleteEvent(AutoCompleteEvent.CLEARING_TEXT));
			searchingText=DEFAULT_SEARCHING_TEXT;
			selectedIndex=DEFAULT_SELECTED_INDEX;
			invalidateSkinState();
		}

		public function searchText():void {
			selectedIndex=DEFAULT_SELECTED_INDEX;
			if (dataProvider && dataProvider is ArrayCollection) {
				(dataProvider as ArrayCollection).refresh();
			}
			invalidateSkinState();
			dispatchEvent(new AutoCompleteEvent(AutoCompleteEvent.SEARCHING));
		}

		public function selectText():void {
			if (!autoSearch) {
				_searchEnabled=false;
			}
			searchingText=selectedItem[labelField];
			invalidateSkinState();
			dispatchEvent(new AutoCompleteEvent(AutoCompleteEvent.ITEM_SELECTED));
		}

		private function filterDataProvider(item:Object):Boolean {
			if (searchingText == '') {
				return true;
			}
			switch (_match) {
				case MATCH_ANY_PART:  {
					var objRef:Object;
					if (labelFunction != null) {
						objRef=labelFunction(item);
					} else if (item.hasOwnProperty(labelField)) {
						objRef=item[labelField];
					}
					if (objRef != null) {
						(objRef as String).match(new RegExp(searchingText, 'i'));

					}
					break;
				}
				case MATCH_BEGINNING:  {
					var str_item:String;
					if (labelFunction != null) {
						str_item=labelFunction(item);
					} else if (item.hasOwnProperty(labelField)) {
						str_item=item[labelField] as String;
					}
					if (str_item != null) {
						return str_item.substr(DEFAULT_FIRST_INDEX, searchingText.length) == searchingText;
					}
					break;
				}
			}
			return true;
		}

		private function textInput_keyDownHandler(event:KeyboardEvent):void {
			if (scroller) {
				scroller.focusManager=focusManager;
			}
			if (event.keyCode == Keyboard.DOWN) {
				if (dataGroup) {
					dataGroup.setFocus();
				}
			}
		}

		private function textInput_keyUpHandler(event:KeyboardEvent):void {
			if (event.keyCode == Keyboard.DOWN) {
				textInput.selectRange(searchingText.length, searchingText.length);
			} else {
				if (autoSearch) {
					_searchEnabled=true;
					searchText();
				} else {
					if (searchEnabled) {
						searchText();
						_searchEnabled=false;
					}
				}
			}
		}

		private function clearButton_clickHandler(event:MouseEvent):void {
			clearText();
		}

		private function searchButton_clickHandler(event:MouseEvent):void {
			_searchEnabled=true;
			searchText();
		}

		private function dataGroup_changeHandler(event:Event):void {
			//selectedIndex = dataProvider.getItemIndex(super.selectedItem);
			dispatchEvent(new Event(Event.CHANGE));
		}

		private function dataGroup_keyDownHandler(event:KeyboardEvent):void {
			if (event.keyCode == Keyboard.DOWN) {
				if (selectedIndex <= dataProvider.length - 1) {
					selectedIndex++;
						//adjustSelectionAndCaretUponNavigation(event);
				}
			} else if (event.keyCode == Keyboard.UP) {
				if (selectedIndex > DEFAULT_SELECTED_INDEX) {
					selectedIndex--;
						//adjustSelectionAndCaretUponNavigation(event);
				}
			}
			if (event.charCode == Keyboard.ENTER) {
				selectText();
			}
		}

		private function dataGroup_clickHandler(event:MouseEvent):void {
			selectText();
		}
	}
}
